package com.dferreira.repository.services;

import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
import android.util.Log;

import com.dferreira.languagesteach.LanguagesTeachApplication;
import com.dferreira.languagesteach.utils.DataPaths;
import com.dferreira.repository.RepositoryDatabaseHelper;
import com.dferreira.repository.data_models.RepositoryPackage;
import com.dferreira.repository.data_delegators.RepositoryDataSource;

import java.util.HashMap;


/**
 * An {@link IntentService} subclass for handling asynchronous task requests in
 * a service on a separate handler thread.
 * <p/>
 * Handles the installation or uninstall de packages of languages
 * TODO: Customize class - update intent actions, extra parameters and static
 * helper methods.
 */
public class PackageManagerService extends IntentService {
    /*Constants*/
    private static final String TAG = "PackageManagerService";
    private static final String SERVICE_NAME = "PackageManagerService";
    private static final String ACTION_INSTALL = "com.dferreira.repository.services.action.install";
    private static final String ACTION_UNINSTALL = "com.dferreira.repository.services.action.uninstall";
    private static final String PACKAGE_SIZE = "com.dferreira.repository.services.extra.package_size";
    private static final String PACKAGE_NAME = "com.dferreira.repository.services.extra.package_name";
    private static final long DEFAULT_PACKAGE_SIZE = 0L;

    private static HashMap<String, PackageInstallerState> packageInstallerStates = packageInstallerStates = new HashMap<String, PackageInstallerState>();
    private final DataPaths dataPaths;
    private final RepositoryDatabaseHelper repositoryDbHelper;
    private final RepositoryNotifier repositoryNotifier;
    private final PackageInstaller packageInstaller;

    //TODO
    private final PackageUnInstaller packageUnInstaller;
    private final RepositoryDataSource remoteDataSource;


    /**
     *
     */
    public PackageManagerService() {
        super(SERVICE_NAME);

        Context context = LanguagesTeachApplication.getContext();

        this.dataPaths = new DataPaths(context);
        this.repositoryDbHelper = new RepositoryDatabaseHelper(context);
        this.repositoryNotifier = new RepositoryNotifier(context);
        this.remoteDataSource = new RepositoryDataSource(context);
        this.packageInstaller = new PackageInstaller(context, this.dataPaths, this.repositoryDbHelper, this.repositoryNotifier);
        //TODO
        this.packageUnInstaller = new PackageUnInstaller();
    }

    /**
     * Starts this service to perform action install with the given parameters. If
     * the service is already performing a task this action will be queued.
     *
     * @see IntentService
     */
    public static void installPackage(Context context, long totalBytesToInstall, String packageName) {
        Intent intent = new Intent(context, PackageManagerService.class);
        intent.setAction(ACTION_INSTALL);
        intent.putExtra(PACKAGE_SIZE, totalBytesToInstall);
        intent.putExtra(PACKAGE_NAME, packageName);
        context.startService(intent);
    }

    /**
     * Starts this service to perform action uninstall with the given parameters. If
     * the service is already performing a task this action will be queued.
     *
     * @see IntentService
     */
    public static void uninstallPkg(Context context, String packageName) {
        Intent intent = new Intent(context, PackageManagerService.class);
        intent.setAction(ACTION_UNINSTALL);
        intent.putExtra(PACKAGE_NAME, packageName);
        context.startService(intent);
    }

    /**
     * @param intent
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            final String packageName = intent.getStringExtra(PACKAGE_NAME);
            final RepositoryPackage repositoryPackage = remoteDataSource.getPackageInfo(packageName);
            final Long packageSize = intent.getLongExtra(PACKAGE_SIZE, DEFAULT_PACKAGE_SIZE);
            if (ACTION_INSTALL.equals(action)) {
                handleInstallAction(repositoryPackage, packageSize);
            } else if (ACTION_UNINSTALL.equals(action)) {
                handleUninstallAction(repositoryPackage, packageSize);
            }
        }
    }


    /**
     * @param packageName
     * @param packageSize
     * @return
     */
    private static PackageInstallerState getPackageInstallerState(String packageName, Long packageSize) {
        if (!packageInstallerStates.containsKey(packageName)) {
            packageInstallerStates.put(packageName, new PackageInstallerState(packageName, packageSize));
        }
        return packageInstallerStates.get(packageName);
    }

    /**
     * @param packageName
     */
    private static void removePackageInstallerState(String packageName) {
        if (packageInstallerStates.containsKey(packageName)) {
            packageInstallerStates.remove(packageName);
        }
    }

    /**
     * Handle action install in the provided background thread with the provided
     * parameters.
     */
    private void handleInstallAction(RepositoryPackage repositoryPackage, Long packageSize) {
        PackageInstallerState packageInstallerState = getPackageInstallerState(repositoryPackage.getName(), packageSize);
        packageInstaller.installPackage(repositoryPackage, packageInstallerState);
        removePackageInstallerState(repositoryPackage.getName());
    }

    /**
     * Handle action uninstall in the provided background thread with the provided
     * parameters.
     */
    private void handleUninstallAction(RepositoryPackage repositoryPackage, Long packageSize) {
        // TODO: Handle action uninstall
        Log.i(TAG, "uninstalling:" + repositoryPackage.getName());
    }

    /**
     * @param packageName
     */
    public void cancelInstallation(String packageName) {
        //TODO
        throw new UnsupportedOperationException();
    }


    /**
     * @param packageName
     * @return
     */
    public static Integer getPackageInstallationProgress(String packageName) {
        if (packageInstallerStates.containsKey(packageName)) {
            PackageInstallerState packageInstallerState = packageInstallerStates.get(packageName);
            if (packageInstallerState.isInstalling()) {
                return (int) ((100.0f * packageInstallerState.getTotalBytesInstalled()) / packageInstallerState.getTotalBytesToInstall());
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
}
